#include "Random_isaac.h"
#include <limits.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

const int Modular = 10;

const long long COUNTER_LIMIT = 100LL;

Random_isaac::Random_isaac()
{
    resetSeeds();
}

Random_isaac::~Random_isaac()
{
}

bool Random_isaac::isDiscard(int number, unsigned int m)
{
    if (m == 0) {
        return false;
    }
    int threshold = INT_MAX - 1 - (INT_MAX - 1) % m;
    if ( number > threshold )
        return true;
    else
        return false;
}

unsigned long Random_isaac::nextInt(unsigned long m)
{
    if (counter > COUNTER_LIMIT)
        resetSeeds();

    int rndnumber = rand();
    int skip_times = rndnumber % Modular + 1;
    int r;
    long seed1, seed2;

    for ( int i = 0 ; i < skip_times; ++ i ) {
        r = _issac.rand();
    }
    while ( isDiscard(r, m) ) {
        r = _issac.rand();
        counter ++;
    }

    return r;
}

void Random_isaac::resetSeeds()
{
    FILE *ptrnd;
    ptrnd = fopen("/dev/urandom", "r");
    assert(ptrnd);

    unsigned char rndnumber[64];
    fread((void *)rndnumber, 1, sizeof(rndnumber), ptrnd);
    memcpy((char *)_randctx.randrsl, (char *)rndnumber, sizeof(rndnumber));
    _issac.randinit(&_randctx, true);

    counter = 0;

    unsigned int ran2;
    fread((void *)(&ran2), 1, sizeof(unsigned int), ptrnd);
    srand(ran2);
    if (ptrnd) {
        fclose(ptrnd);
        ptrnd = NULL;
    }
}
